from typing import List, Dict, Any, Optional
from datetime import datetime
from dataclasses import dataclass

from ..models.classroom import ClassroomRequest
from ..models.audit_models import RuleResult
from ..utils.logger import get_logger

logger = get_logger(__name__)


@dataclass
class SimpleRuleResult:
    """简化的规则检查结果."""
    passed: bool
    score: float
    message: str
    details: Optional[Dict[str, Any]] = None
    
    @property
    def matched(self) -> bool:
        """提供matched属性以兼容AuditWorkflow接口."""
        return self.passed
    
    @property
    def rule_name(self) -> str:
        """提供rule_name属性以兼容AuditWorkflow接口."""
        return self.message
    
    @property
    def score_impact(self) -> float:
        """提供score_impact属性以兼容AuditWorkflow接口."""
        return self.score
    
    @property
    def execution_time_ms(self) -> float:
        """提供execution_time_ms属性以兼容AuditWorkflow接口."""
        return 0.1  # 模拟执行时间


class SimpleClassroomRuleEngine:
    """简化的教室审核规则引擎，只基于用户提供的信息进行评判."""
    
    def __init__(self):
        self.rules = [
            self.check_user_category_priority,
            self.check_borrow_type_appropriateness,
            self.check_borrow_category_match,
            self.check_equipment_request_reasonableness,
            self.check_room_info_completeness,
            self.check_application_description_quality,
            self.check_time_description_clarity,
            self.check_materials_adequacy
        ]
    
    def execute_rules(self, request: ClassroomRequest) -> List[RuleResult]:
        """执行所有规则检查."""
        results = []
        
        for i, rule_func in enumerate(self.rules):
            try:
                start_time = datetime.now()
                result = rule_func(request)
                end_time = datetime.now()
                execution_time = (end_time - start_time).total_seconds() * 1000
                
                # 转换为RuleResult
                rule_result = RuleResult(
                    rule_id=f"rule_{i+1}",
                    rule_name=rule_func.__name__,
                    matched=result.passed,
                    score_impact=result.score,
                    message=result.message,
                    execution_time_ms=execution_time
                )
                results.append(rule_result)
                
            except Exception as e:
                logger.error(f"规则 {rule_func.__name__} 执行失败: {str(e)}")
                # 添加一个失败的结果
                rule_result = RuleResult(
                    rule_id=f"rule_{i+1}",
                    rule_name=rule_func.__name__,
                    matched=False,
                    score_impact=-5.0,
                    message=f"规则执行异常: {str(e)}",
                    execution_time_ms=0.0
                )
                results.append(rule_result)
        
        return results
    
    def calculate_total_score(self, results: List[RuleResult]) -> float:
        """计算总分."""
        base_score = 50.0  # 基础分
        
        for result in results:
            base_score += result.score_impact
        
        # 确保分数在0-100范围内
        return max(0.0, min(100.0, base_score))
    
    def check_user_category_priority(self, request: ClassroomRequest) -> SimpleRuleResult:
        """检查用户类别优先级."""
        try:
            user_category = request.user_category.lower()
            
            # 根据用户类别给出不同的评分
            if any(keyword in user_category for keyword in ["教师", "老师", "professor", "teacher"]):
                return SimpleRuleResult(
                    passed=True,
                    score=20,
                    message=f"用户类别: {request.user_category} (教师优先级)"
                )
            elif any(keyword in user_category for keyword in ["管理员", "admin", "staff"]):
                return SimpleRuleResult(
                    passed=True,
                    score=25,
                    message=f"用户类别: {request.user_category} (管理员优先级)"
                )
            elif any(keyword in user_category for keyword in ["研究生", "graduate", "硕士", "博士"]):
                return SimpleRuleResult(
                    passed=True,
                    score=15,
                    message=f"用户类别: {request.user_category} (研究生优先级)"
                )
            elif any(keyword in user_category for keyword in ["本科生", "undergraduate", "学生"]):
                return SimpleRuleResult(
                    passed=True,
                    score=10,
                    message=f"用户类别: {request.user_category} (学生优先级)"
                )
            else:
                return SimpleRuleResult(
                    passed=True,
                    score=5,
                    message=f"用户类别: {request.user_category} (其他类别)"
                )
                
        except Exception as e:
            return SimpleRuleResult(
                passed=False,
                score=-5,
                message=f"用户类别检查异常: {str(e)}"
            )
    
    def check_borrow_type_appropriateness(self, request: ClassroomRequest) -> SimpleRuleResult:
        """检查借用类型的合理性."""
        try:
            borrow_type = request.borrow_type.lower()
            
            # 根据借用类型给出评分
            if "教学" in borrow_type:
                return SimpleRuleResult(
                    passed=True,
                    score=20,
                    message=f"借用类型: {request.borrow_type} (教学活动优先级高)"
                )
            elif "班级活动" in borrow_type:
                return SimpleRuleResult(
                    passed=True,
                    score=15,
                    message=f"借用类型: {request.borrow_type} (班级活动优先级中等)"
                )
            elif "社团活动" in borrow_type:
                return SimpleRuleResult(
                    passed=True,
                    score=10,
                    message=f"借用类型: {request.borrow_type} (社团活动需适度控制)"
                )
            elif "涉外活动" in borrow_type:
                return SimpleRuleResult(
                    passed=True,
                    score=12,
                    message=f"借用类型: {request.borrow_type} (涉外活动需特别审核)"
                )
            else:
                return SimpleRuleResult(
                    passed=True,
                    score=5,
                    message=f"借用类型: {request.borrow_type} (其他活动类型)"
                )
                
        except Exception as e:
            return SimpleRuleResult(
                passed=False,
                score=-5,
                message=f"借用类型检查异常: {str(e)}"
            )
    
    def check_borrow_category_match(self, request: ClassroomRequest) -> SimpleRuleResult:
        """检查借用类别的匹配度."""
        try:
            borrow_type = request.borrow_type.lower()
            borrow_category = request.borrow_category.lower()
            
            # 检查类型和类别的匹配度
            teaching_categories = ["上课", "培训", "讲座"]
            exam_categories = ["考试"]
            meeting_categories = ["开会", "活动"]
            study_categories = ["自习"]
            
            if "教学" in borrow_type:
                if any(cat in borrow_category for cat in teaching_categories):
                    return SimpleRuleResult(
                        passed=True,
                        score=15,
                        message=f"借用类别 '{request.borrow_category}' 与教学类型匹配"
                    )
                else:
                    return SimpleRuleResult(
                        passed=False,
                        score=-10,
                        message=f"借用类别 '{request.borrow_category}' 与教学类型不够匹配"
                    )
            
            elif "活动" in borrow_type:
                if any(cat in borrow_category for cat in meeting_categories):
                    return SimpleRuleResult(
                        passed=True,
                        score=10,
                        message=f"借用类别 '{request.borrow_category}' 与活动类型匹配"
                    )
            
            # 默认情况：类别合理
            return SimpleRuleResult(
                passed=True,
                score=8,
                message=f"借用类别: {request.borrow_category}"
            )
                
        except Exception as e:
            return SimpleRuleResult(
                passed=False,
                score=-5,
                message=f"借用类别匹配检查异常: {str(e)}"
            )
    
    def check_equipment_request_reasonableness(self, request: ClassroomRequest) -> SimpleRuleResult:
        """检查设备申请的合理性."""
        try:
            if not request.need_equipment:
                return SimpleRuleResult(
                    passed=True,
                    score=10,
                    message="无设备需求，减少使用复杂度"
                )
            
            # 有设备需求但没有详细描述
            if not request.equipment_description or len(request.equipment_description.strip()) < 10:
                return SimpleRuleResult(
                    passed=False,
                    score=-15,
                    message="申请设备但未提供详细设备需求说明"
                )
            
            # 设备需求描述合理
            equipment_desc = request.equipment_description.lower()
            
            # 检查常见设备需求
            if any(equipment in equipment_desc for equipment in 
                   ["投影仪", "音响", "话筒", "电脑", "网络", "projector", "speaker", "microphone"]):
                return SimpleRuleResult(
                    passed=True,
                    score=5,
                    message="设备需求合理且描述清晰"
                )
            else:
                return SimpleRuleResult(
                    passed=True,
                    score=0,
                    message="设备需求已说明，需人工确认可用性"
                )
                
        except Exception as e:
            return SimpleRuleResult(
                passed=False,
                score=-5,
                message=f"设备需求检查异常: {str(e)}"
            )
    
    def check_room_info_completeness(self, request: ClassroomRequest) -> SimpleRuleResult:
        """检查房间信息完整性."""
        try:
            room_info = request.room_info.strip()
            
            if len(room_info) < 10:
                return SimpleRuleResult(
                    passed=False,
                    score=-20,
                    message="房间信息描述过于简单，缺乏必要信息"
                )
            
            # 检查是否包含关键信息
            info_lower = room_info.lower()
            has_capacity = any(keyword in info_lower for keyword in 
                             ["容量", "座位", "人数", "capacity", "seats"])
            has_equipment = any(keyword in info_lower for keyword in 
                              ["设备", "投影", "音响", "网络", "equipment", "projector"])
            has_location = any(keyword in info_lower for keyword in 
                             ["楼", "层", "room", "教室", "building"])
            
            score = 0
            details = []
            
            if has_capacity:
                score += 8
                details.append("包含容量信息")
            if has_equipment:
                score += 8
                details.append("包含设备信息")
            if has_location:
                score += 4
                details.append("包含位置信息")
            
            if not details:
                return SimpleRuleResult(
                    passed=False,
                    score=-10,
                    message="房间信息缺乏关键要素（容量、设备、位置）"
                )
            
            return SimpleRuleResult(
                passed=True,
                score=score,
                message=f"房间信息包含: {', '.join(details)}"
            )
                
        except Exception as e:
            return SimpleRuleResult(
                passed=False,
                score=-5,
                message=f"房间信息检查异常: {str(e)}"
            )
    
    def check_application_description_quality(self, request: ClassroomRequest) -> SimpleRuleResult:
        """检查申请说明质量."""
        try:
            description = request.application_description.strip()
            
            if len(description) < 20:
                return SimpleRuleResult(
                    passed=False,
                    score=-15,
                    message="申请说明过于简单，缺乏详细信息"
                )
            
            # 检查说明的完整性
            desc_lower = description.lower()
            has_purpose = any(keyword in desc_lower for keyword in 
                            ["目的", "原因", "为了", "purpose", "reason"])
            has_details = any(keyword in desc_lower for keyword in 
                            ["内容", "安排", "流程", "活动", "课程"])
            has_participants = any(keyword in desc_lower for keyword in 
                                 ["人数", "参与", "学生", "人员", "participants"])
            
            score = 5  # 基础分
            details = []
            
            if has_purpose:
                score += 8
                details.append("说明了使用目的")
            if has_details:
                score += 8
                details.append("提供了活动细节")
            if has_participants:
                score += 4
                details.append("描述了参与情况")
            
            if len(description) > 100:
                score += 5
                details.append("描述详细")
            
            return SimpleRuleResult(
                passed=True,
                score=score,
                message=f"申请说明质量: {', '.join(details) if details else '基本合格'}"
            )
                
        except Exception as e:
            return SimpleRuleResult(
                passed=False,
                score=-5,
                message=f"申请说明检查异常: {str(e)}"
            )
    
    def check_time_description_clarity(self, request: ClassroomRequest) -> SimpleRuleResult:
        """检查时间描述的清晰度."""
        try:
            time_desc = request.time_description.strip()
            
            if len(time_desc) < 10:
                return SimpleRuleResult(
                    passed=False,
                    score=-20,
                    message="时间描述过于简单，无法确定具体使用时间"
                )
            
            # 检查时间信息的完整性
            desc_lower = time_desc.lower()
            has_date = any(keyword in desc_lower for keyword in 
                          ["日", "月", "年", "周", "date", "day", "月份"])
            has_time = any(keyword in desc_lower for keyword in 
                          ["点", "时", "分", "hour", "time", ":"])
            has_duration = any(keyword in desc_lower for keyword in 
                             ["小时", "分钟", "duration", "长", "到"])
            
            score = 0
            details = []
            
            if has_date:
                score += 10
                details.append("包含日期信息")
            if has_time:
                score += 10
                details.append("包含具体时间")
            if has_duration:
                score += 5
                details.append("说明了使用时长")
            
            if not details:
                return SimpleRuleResult(
                    passed=False,
                    score=-15,
                    message="时间描述缺乏关键要素（日期、时间、时长）"
                )
            
            return SimpleRuleResult(
                passed=True,
                score=score,
                message=f"时间信息: {', '.join(details)}"
            )
                
        except Exception as e:
            return SimpleRuleResult(
                passed=False,
                score=-5,
                message=f"时间描述检查异常: {str(e)}"
            )
    
    def check_materials_adequacy(self, request: ClassroomRequest) -> SimpleRuleResult:
        """检查申请材料充分性."""
        try:
            if not request.application_materials:
                # 根据借用类型判断是否需要材料
                borrow_type = request.borrow_type.lower()
                
                if "涉外" in borrow_type or "社团" in borrow_type:
                    return SimpleRuleResult(
                        passed=False,
                        score=-10,
                        message=f"{request.borrow_type}通常需要提供相关证明材料"
                    )
                else:
                    return SimpleRuleResult(
                        passed=True,
                        score=0,
                        message="未提供申请材料（根据借用类型可能不需要）"
                    )
            
            # 有材料说明
            materials = request.application_materials.strip()
            
            if len(materials) < 10:
                return SimpleRuleResult(
                    passed=False,
                    score=-5,
                    message="申请材料描述过于简单"
                )
            
            # 检查材料类型
            materials_lower = materials.lower()
            material_types = []
            
            if any(keyword in materials_lower for keyword in 
                   ["申请书", "申请表", "application"]):
                material_types.append("申请表")
            if any(keyword in materials_lower for keyword in 
                   ["证明", "许可", "approval", "certificate"]):
                material_types.append("相关证明")
            if any(keyword in materials_lower for keyword in 
                   ["计划", "方案", "plan", "schedule"]):
                material_types.append("活动计划")
            
            if material_types:
                return SimpleRuleResult(
                    passed=True,
                    score=10,
                    message=f"提供了申请材料: {', '.join(material_types)}"
                )
            else:
                return SimpleRuleResult(
                    passed=True,
                    score=5,
                    message="已说明申请材料情况"
                )
                
        except Exception as e:
            return SimpleRuleResult(
                passed=False,
                score=-5,
                message=f"申请材料检查异常: {str(e)}"
            )


def create_audit_summary(request: ClassroomRequest, results: List[SimpleRuleResult], 
                        final_score: float) -> Dict[str, Any]:
    """创建审核摘要."""
    
    passed_rules = [r for r in results if r.passed]
    failed_rules = [r for r in results if not r.passed]
    
    # 生成决策
    if final_score >= 80:
        decision = "approved"
        decision_reason = "申请信息完整，符合借用要求"
    elif final_score >= 60:
        decision = "conditional"
        decision_reason = "申请基本符合要求，建议补充完善部分信息后批准"
    elif final_score >= 40:
        decision = "pending"
        decision_reason = "申请存在多个问题，需要人工审核"
    else:
        decision = "rejected"
        decision_reason = "申请信息不完整或不符合借用要求"
    
    # 生成风险因素
    risk_factors = []
    for rule in failed_rules:
        if rule.score <= -10:
            risk_factors.append(rule.message)
    
    # 生成建议
    recommendations = []
    if decision in ["conditional", "pending"]:
        for rule in failed_rules:
            if "缺乏" in rule.message or "过于简单" in rule.message:
                recommendations.append(f"请补充: {rule.message}")
    
    if decision == "approved":
        recommendations = ["请按时使用教室", "使用完毕后请及时清理", "如有特殊需求请提前联系管理员"]
    elif not recommendations:
        recommendations = ["请根据审核意见完善申请信息", "如有疑问请联系审核人员"]
    
    return {
        "decision": decision,
        "decision_reason": decision_reason,
        "final_score": final_score,
        "passed_rules": len(passed_rules),
        "failed_rules": len(failed_rules),
        "risk_factors": risk_factors,
        "recommendations": recommendations,
        "detailed_feedback": [r.message for r in results]
    }